package ch08
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;

	import utils.Ball;

	/**
	 * 弹簧连接多个物体.
	 * 物体之间由一根弹簧连接。其中一个运动了，另一个物体就要向该物体移动过来。
	 * @author sjp
	 *
	 */
	public class DoubleSpring extends Sprite
	{
		private var ball0:Ball;
		private var ball1:Ball;
		private var ball2:Ball;
		private var ball0Dragging:Boolean=false;
		private var ball1Dragging:Boolean=false;
		private var ball2Dragging:Boolean=false;
		private var spring:Number=0.1;
		private var friction:Number=0.95;
		//弹簧的长度为 100 像素
		private var springLength:Number=100;

		public function DoubleSpring()
		{
			init();
		}

		private function init():void
		{
			ball0=new Ball(20);
			ball0.x=Math.random() * stage.stageWidth;
			ball0.y=Math.random() * stage.stageHeight;
			ball0.addEventListener(MouseEvent.MOUSE_DOWN, onPress);
			addChild(ball0);
			ball1=new Ball(20);
			ball1.x=Math.random() * stage.stageWidth;
			ball1.y=Math.random() * stage.stageHeight;
			ball1.addEventListener(MouseEvent.MOUSE_DOWN, onPress);
			addChild(ball1);
			ball2=new Ball(20);
			ball2.x=Math.random() * stage.stageWidth;
			ball2.y=Math.random() * stage.stageHeight;
			ball2.addEventListener(MouseEvent.MOUSE_DOWN, onPress);
			addChild(ball2);
			addEventListener(Event.ENTER_FRAME, onEnterFrame);
			stage.addEventListener(MouseEvent.MOUSE_UP, onRelease);
		}

		private function onEnterFrame(event:Event):void
		{
			/**
			 * springTo 函数用于产生运动，函数中的所有语句大家应该都很熟悉。
			 * 首先，求出距离和角度，再计算目标点，然后向目标点运动。
			 * 第二次调用函数时，参数相反，两个小球交换位置，开始的小球向另一个小球运动。
			 * 这也许不是效率最高的代码，但是它可以最好地表现出运动的过程。
			 */
			if (!ball0Dragging)
			{
				springTo(ball0, ball1);
				springTo(ball0, ball2);
			}
			if (!ball1Dragging)
			{
				springTo(ball1, ball0);
				springTo(ball1, ball2);
			}
			if (!ball2Dragging)
			{
				springTo(ball2, ball0);
				springTo(ball2, ball1);
			}
			graphics.clear();
			graphics.lineStyle(1);
			graphics.moveTo(ball0.x, ball0.y);
			graphics.lineTo(ball1.x, ball1.y);
			graphics.lineTo(ball2.x, ball2.y);
			graphics.lineTo(ball0.x, ball0.y);
			graphics.endFill();
		}


		private function springTo(ballA:Ball, ballB:Ball):void
		{
			var dx:Number=ballA.x - ballB.x;
			var dy:Number=ballA.y - ballB.y;
			var angle:Number=Math.atan2(dy, dx);
			var targetX:Number=ballB.x + Math.cos(angle) * springLength;
			var targetY:Number=ballB.y + Math.sin(angle) * springLength;
			ballA.vx+=(targetX - ballA.x) * spring;
			ballA.vy+=(targetY - ballA.y) * spring;
			ballA.vx*=friction;
			ballA.vy*=friction;
			ballA.x+=ballA.vx;
			ballA.y+=ballA.vy;
		}

		private function onPress(event:MouseEvent):void
		{
			event.target.startDrag();
			if (event.target == ball0)
			{
				ball0Dragging=true;
			}
			if (event.target == ball1)
			{
				ball1Dragging=true;
			}
			if (event.target == ball2)
			{
				ball2Dragging=true;
			}
		}

		private function onRelease(event:MouseEvent):void
		{
			ball0.stopDrag();
			ball1.stopDrag();
			ball2.stopDrag();
			ball0Dragging=false;
			ball1Dragging=false;
			ball2Dragging=false;
		}
	}
}